#include "widgetplayfile.h"
#include "ui_widgetplayfile.h"
#include <QDebug>
#include <QMessageBox>

WidgetPlayFile::WidgetPlayFile(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::WidgetPlayFile)
{
    ui->setupUi(this);
    //初始化指针
    m_pOutput = NULL;
    //采样点数据类型，序号就是类型数值 0,1,2,3
    m_listSampleTypes<<"Unknown"<<"SignedInt"<<"UnSignedInt"<<"Float";
    //初始化，获取设备列表
    InitFindDevices();
}

WidgetPlayFile::~WidgetPlayFile()
{
    //如果指针不空就删除
    if(NULL != m_pOutput)
    {
        delete m_pOutput;   m_pOutput = NULL;
    }
    //销毁窗口
    delete ui;
}

//初始化，获取音频输出设备
void WidgetPlayFile::InitFindDevices()
{
    //获取输出设备列表
    m_listDevices = QAudioDeviceInfo::availableDevices( QAudio::AudioOutput );
    //添加到组合框
    for(int i=0; i<m_listDevices.count(); i++)
    {
        ui->comboBoxDeviceOut->addItem( m_listDevices[i].deviceName() );
    }
    //设置默认播放文件名
    ui->lineEditFile->setText( "E:/audio_8k1c8bit.pcm" );
    //设置进度条范围
    ui->horizontalSlider->setRange(0, 100);
}

//设备名变化时，自动更新设备支持的播放参数
void WidgetPlayFile::on_comboBoxDeviceOut_currentIndexChanged(int index)
{
    if(index < 0)   return; //序号不合法，直接返回
    //序号合法
    //根据设备支持的采样频率设置组合框
    QList<int> listSampleRates = m_listDevices[index].supportedSampleRates();
    //清空旧的组合框条目
    ui->comboBoxSampleRate->clear();
    //添加新的
    for(int i=0; i<listSampleRates.count(); i++)
    {
        ui->comboBoxSampleRate->addItem( tr("%1").arg( listSampleRates[i] ) );
    }
    //通道数列表
    QList<int> listChannels = m_listDevices[index].supportedChannelCounts();
    //清空旧的
    ui->comboBoxChannelCount->clear();
    //添加新的
    for(int i=0; i<listChannels.count(); i++)
    {
        ui->comboBoxChannelCount->addItem( tr("%1").arg( listChannels[i] ) );
    }
    //采样位宽列表
    QList<int> listSizes = m_listDevices[index].supportedSampleSizes();
    //清空旧的
    ui->comboBoxSampleSize->clear();
    //添加新的
    for(int i=0; i<listSizes.count(); i++)
    {
        ui->comboBoxSampleSize->addItem( tr("%1").arg( listSizes[i] ) );
    }
    //采样点数据类型
    QList<QAudioFormat::SampleType> listTypes = m_listDevices[index].supportedSampleTypes();
    //清空旧的
    ui->comboBoxSampleType->clear();
    //添加新的
    for(int i=0; i<listTypes.count(); i++)
    {
        QString strType = m_listSampleTypes[ listTypes[i] ];
        //第一个参数是显示字符串，第二个参数用户数据保存采样类型值，方便后面提取类型值
        ui->comboBoxSampleType->addItem( strType, listTypes[i] );
    }
    //如果默认位宽是 8，设置默认无符号整数
    if( 8 == listSizes[0] )
    {
        //无符号整数
        ui->comboBoxSampleType->setCurrentText( m_listSampleTypes[2] );
    }
    else
    {
        //其他情况用有符号整数
        ui->comboBoxSampleType->setCurrentText( m_listSampleTypes[1] );
    }
}

//开始播放文件
void WidgetPlayFile::on_pushButtonStart_clicked()
{
    //如果没有声卡不处理
    if( m_listDevices.count() < 1 )
    {
        return;
    }
    //先尝试以只读模式打开文件
    m_filePlay.setFileName( ui->lineEditFile->text() );
    if( ! m_filePlay.open( QIODevice::ReadOnly ) )
    {
        //无法打开
        QMessageBox::warning(this, tr("打开文件"), tr("无法打开指定文件，不能播放。"));
        return;
    }
    //成功打开文件
    //获取用户选择的声卡设备
    QAudioDeviceInfo dev = m_listDevices[ ui->comboBoxDeviceOut->currentIndex() ];
    //设置播放的音频格式
    //采样频率
    m_aFormat.setSampleRate( ui->comboBoxSampleRate->currentText().toInt() );
    //通道数
    m_aFormat.setChannelCount( ui->comboBoxChannelCount->currentText().toInt() );
    //采样位宽
    m_aFormat.setSampleSize( ui->comboBoxSampleSize->currentText().toInt() );
    //采样点数据类型
    QAudioFormat::SampleType curType =
            (QAudioFormat::SampleType)( ui->comboBoxSampleType->currentData().toInt() );
    m_aFormat.setSampleType( curType );
    //字节序不设置
    //编码格式固定用 PCM
    m_aFormat.setCodec( "audio/pcm" );
    //判断格式是否支持
    if( !dev.isFormatSupported( m_aFormat ) )
    {
        qDebug()<<"old audioFormat is not supported: "<<endl<<m_aFormat;
        m_aFormat = dev.nearestFormat( m_aFormat );
    }
    qDebug()<<"used Format: "<<endl<<m_aFormat<<endl;
    //新建音频输出对象
    m_pOutput = new QAudioOutput(dev, m_aFormat);
    //设置定时通知信号的时间间隔，40ms
    m_pOutput->setNotifyInterval( 40 );
    //关联状态变化的信号到槽函数
    connect(m_pOutput, SIGNAL(stateChanged(QAudio::State)),
            this, SLOT(onStateChanged(QAudio::State)) );
    //关联定时通知信号到槽函数
    connect(m_pOutput, SIGNAL(notify()),
            this, SLOT(onNotify()) );
    //开始播放
    m_pOutput->start( &m_filePlay );
    //开始播放后禁用参数控件和开始按钮
    holdParas( true );
}

void WidgetPlayFile::holdParas(bool bHold)
{
    //设置五个组合框、编辑框、开始按钮在开始播放时禁用，停止后启用
    ui->comboBoxDeviceOut->setDisabled( bHold );
    ui->comboBoxSampleRate->setDisabled( bHold );
    ui->comboBoxChannelCount->setDisabled( bHold );
    ui->comboBoxSampleSize->setDisabled( bHold );
    ui->comboBoxSampleType->setDisabled( bHold );
    ui->lineEditFile->setDisabled( bHold );
    ui->pushButtonStart->setDisabled( bHold );
}

void WidgetPlayFile::onStateChanged(QAudio::State state)
{
    qDebug()<<state;
    //如果处于空闲状态，并且文件播放到末尾，那么自动停止
    if( (QAudio::IdleState == state)
            && (m_filePlay.atEnd()) )
    {
        //停止
        on_pushButtonStop_clicked();
    }
}

void WidgetPlayFile::onNotify()
{
    //如果文件没打开就不处理
    if( ! m_filePlay.isOpen() )
    {
        return;
    }
    //计算播放进度
    double percent = m_filePlay.pos()*1.0 /m_filePlay.size() ;
    //设置进度条
    ui->horizontalSlider->setValue( int(percent*100) );
}

void WidgetPlayFile::on_pushButtonPause_clicked()
{
    if( NULL == m_pOutput )//没播放
    {
        return;
    }
    //判断当前播放状态，根据状态的不同分别处理
    QAudio::State state = m_pOutput->state();
    switch (state) {
    case QAudio::ActiveState:
    case QAudio::IdleState: //活跃状态和空闲状态，都执行暂停
        m_pOutput->suspend();
        ui->pushButtonPause->setText( tr("继续") );//切换文本
        break;
    case QAudio::SuspendedState:
        m_pOutput->resume();    //继续
        ui->pushButtonPause->setText( tr("暂停") );//切换文本
        break;
    case QAudio::StoppedState:  //不处理
    default:
        break;
    }
}

void WidgetPlayFile::on_pushButtonStop_clicked()
{
    if( NULL == m_pOutput )//没播放
    {
        return;
    }
    //停止
    m_pOutput->stop();
    //删除输出对象
    delete m_pOutput;   m_pOutput = NULL;
    //关闭文件
    m_filePlay.close();
    //进度条恢复到 0
    ui->horizontalSlider->setValue( 0 );
    //启用参数控件和开始按钮
    holdParas( false );
}
